﻿//
// response.hpp
// ~~~~~~~~
//

#ifndef YUTOPP_RESPONSE_HPP
#define YUTOPP_RESPONSE_HPP

#include "utility/json_parser.hpp"

#include <iostream>
#include <string>
#include <vector>
#include <map>

#include <boost/variant/recursive_variant.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/unordered_map.hpp>
#include <boost/iterator_adaptors.hpp>
#include <boost/range/adaptor/map.hpp>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/optional.hpp>
#include <boost/foreach.hpp>
#include <boost/type_traits.hpp>

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>

namespace webapp
{
	namespace container
	{
		namespace detail
		{
			struct pair_second
			{
				template<typename =void>
				struct result;

				template<typename R, typename Arg>
				struct result<R(Arg)>
				{
					typedef typename boost::remove_reference<
						typename boost::remove_cv<
							Arg
						>::type
					>::type::second_type	type; 
				};

				template<typename Pair>
				typename Pair::second_type operator()( Pair& pair ) const
				{
					return pair.second;
				}
			};
		}

		//APIのレスポンスに簡単にアクセスできるようにしたクラス。
		//そのうち直します・・・；；
		template<class T>
		class basic_response
		{
			typedef basic_response					self_type;
			typedef boost::shared_ptr<self_type>	pointer_type;

		public:
			typedef T								string_type;
			typedef string_type						key_type;
			typedef string_type						value_type;
			typedef std::map<key_type, pointer_type>
													data_type;

			typedef boost::transform_iterator<
				detail::pair_second, typename data_type::iterator
			>										iterator;
			typedef boost::transform_iterator<
				detail::pair_second, typename data_type::const_iterator
			>										const_iterator;


			basic_response()
				: value_( value_type() )
			{}

			basic_response( const key_type& key_name )
				: key_( key_name )
				, value_( data_type() )
			{}

			pointer_type make_node( const key_type& key_name )
			{
				if ( value_.which() != 0 )
					value_ = data_type();

				const auto p = boost::make_shared<self_type>( key_name );
				boost::get<data_type>( value_ ).insert( data_type::value_type( key_name, p ) );
				return p;
			}

			void set_value( const value_type& value )
			{
				value_ = value;
			}

			bool is_leaf() const
			{
				return ( value_.which() == 1 );
			}

			const boost::optional<key_type>& get_key() const
			{
				return key_;
			}

			boost::optional<value_type> get_value() const
			{
				return boost::apply_visitor( value_visitor(), value_ );
			}

			std::size_t count( const key_type& key_name ) const
			{
				assert( value_.which() == 0 );
				return boost::get<data_type>( value_ ).count( key_name );
			}

			const self_type& operator[]( const key_type& key_name ) const
			{
				assert( value_.which() == 0 );
				
				return *boost::get<data_type>( value_ ).at( key_name );
			}

			operator value_type() const
			{
				const auto&& o = boost::apply_visitor( value_visitor(), value_ );
				return o ? *o : value_type();
			}

			//
			const_iterator begin() const
			{
//				return ( boost::get<map_type>( value_ ) | boost::adaptors::map_values ).cbegin();
				return boost::make_transform_iterator(
					boost::get<data_type>( value_ ).cbegin(),
					detail::pair_second()
					);
			}

			const_iterator end() const
			{
				return boost::make_transform_iterator(
					boost::get<data_type>( value_ ).cend(),
					detail::pair_second()
					);
			}

		private:
			//basic_response( const basic_response& );
			//basic_response& operator=( const basic_response& );

			class value_visitor
				: public boost::static_visitor<boost::optional<value_type> >
			{
			public:
				boost::optional<value_type> operator()( const data_type& ) const
				{
					return boost::none;
				}

				boost::optional<value_type> operator()( const value_type& v ) const
				{
					return v;
				}
			};

			boost::optional<key_type> key_;
			boost::variant<data_type, value_type> value_;
		};

		typedef basic_response<std::string>		response;
		typedef basic_response<std::wstring>	wresponse;

		namespace builder
		{
			template<typename T>
			void xml(
				const boost::property_tree::basic_ptree<T, T>& tree,
				container::basic_response<T>& res )
			{
				BOOST_FOREACH( const auto& val, tree ) {
					auto node = res.make_node( val.first );
					const auto& tree = val.second;

					if ( tree.size() == 0 ) {
						node->set_value( tree.data() );
					} else {
						xml( tree, *node );
					}
				}
			}

			//
			class json
				: public boost::static_visitor<void>
			{
			public:
				json( response& r )
					: response_( r )
				{}

				//
				void operator()( const std::string& value ) const
				{
					response_.set_value( value );
				}
	
				//
				void operator()( const util::json::object& expr ) const
				{
					BOOST_FOREACH( const auto& v, expr.children ) {
						const auto node = response_.make_node( v.key );
						boost::apply_visitor( json( *node ), v.node.value );
					}
				}
	
				//
				void operator()( const util::json::array& expr ) const
				{
					size_t i = 0;	//おいまさか・・！
					BOOST_FOREACH( const auto& v, expr.children ) {
						const auto node = response_.make_node( boost::lexical_cast<std::string>( i ) );
						boost::apply_visitor( json( *node ), v.value );
						++i;	//止めろぉぉ！
					}
				}

			private:
				mutable response& response_;
			};
		} // - builder
	}



	//xmlを解析してresponseを返すヘルパ
	template<class Ch>
	container::basic_response<std::basic_string<Ch> >
		xml_tree_helper( const std::basic_string<Ch>& src )
	{
		typedef std::basic_string<Ch>					string_type;
		typedef	container::basic_response<string_type>	response_type;

		response_type res;

		try {
			std::basic_stringstream<Ch> ss;
			ss << src;

			boost::property_tree::basic_ptree<string_type, string_type> root;
			boost::property_tree::read_xml( ss, root );

			container::builder::xml( root, res );	
		}
		catch( const boost::property_tree::xml_parser_error& e )
		{}

		return res;
	}

	//jsonを解析してresponseを返すヘルパ
	template<class Ch>
	container::basic_response<std::basic_string<Ch> >
		json_tree_helper( const std::basic_string<Ch>& src )
	{
		typedef std::basic_string<Ch>					string_type;
		typedef string_type::const_iterator				iterator_type;
		typedef util::json::parser/*<iterator_type>*/		parser_type;
		typedef	container::basic_response<string_type>	response_type;


		const string_type sjis_str = encoding::sjis( src );
		iterator_type begin	= sjis_str.cbegin();
		iterator_type end	= sjis_str.cend();

		parser_type parser;
		util::json::node_value node;

		response_type res;
		const bool r = boost::spirit::qi::phrase_parse( begin, end, parser, util::json::standard::space, node );
		if ( r && begin == end ) {
			boost::apply_visitor( container::builder::json( res ), node.value );
		} else {
			//
		}
		return res;
	}

} // - webapp

#endif /*YUTOPP_RESPONSE_HPP*/